package edu.fau.scanny.r;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.rosuda.REngine.REXP;
import org.rosuda.REngine.REXPMismatchException;
import org.rosuda.REngine.REngineException;
import org.rosuda.REngine.Rserve.RConnection;

public class RUtils {

	public enum library {
		PRACMA, SIMPLEAFFY
	}

	public static String[] colors = new String[] { "darkred", "darkorchid4", "darkorange4", "darkolivegreen4", "darkmagenta", "darkkhaki",
			"darkgrey", "darkgreen", "darkgoldenrod4", "darkcyan", "darkblue", "cornsilk4", "cornflowerblue", "coral4", "chocolate4", "chartreuse4",
			"cadetblue4", "burlywood4", "brown4", "blueviolet", "blue4", "black", "bisque4", "azure4", "aquamarine4", "antiquewhite4" };

	public static String asCharacter(String var){
		return String.format("as.character(%s)",var);
	}
	
	public static String unlist(String var){
		return String.format("unlist(%s)", var);
	}
	
	public static String match(String match1, String match2){
		return String.format("match(%s,%s)", match1,match2);
	}
	public static void abline(RConnection rc, String xx, String yy, String col) throws REngineException, REXPMismatchException {
		RUtils.runRExp(rc, String.format("abline(%s,%s,col=%s);", xx, yy,col));
	}
	
	public static String median(String list, Boolean na) throws REngineException, REXPMismatchException {
		return String.format("median(%s, na.rm= %s)", list, StringUtils.upperCase(na.toString()));
	}
	
	public static String quantile(String list, Double quantile, Boolean na) throws REngineException, REXPMismatchException {
		return String.format("quantile(%s,%s, na.rm= %s)", list,quantile, StringUtils.upperCase(na.toString()));
	}

	public static void assign(RConnection rc, String rFunction, String varAssign) throws REngineException, REXPMismatchException {
		RUtils.runRExp(rc, String.format("%s=%s", varAssign, rFunction));
	}
	
//	if no row names then pass in string "NULL"
	public static String readTable(String table, Boolean header, String rowNames, String separation, Boolean asIs){
		String readTable = String.format("read.table(\"%s\",header=%s,row.names=%s,sep=\"%s\",as.is=%s)", table, StringUtils.upperCase(header.toString()), rowNames, separation, StringUtils.upperCase(asIs.toString()));
		return readTable;
	}

	// public static String mget(RConnection rc, String tableVarName, String
	// get, String listVar) throws REngineException, REXPMismatchException{
	// return
	// String.format("mget(rownames(%s),%s,ifnotfound=NA)->>%s;",tableVarName,get,
	// listVar);
	// }

	public static String tableColumn(String table, Integer column){
		String tableColumn = String.format("%s[,%s]", table, column);
		return tableColumn;
	}
	
	public static String rownames(String table){
		return String.format("rownames(%s)", table);
	}
	
	public static void assignRowNames(RConnection rc, String tableVarFrom, String tableVarTo) throws REngineException, REXPMismatchException {
		String rowNames = String.format("rownames(%s)->rownames(%s);", tableVarFrom, tableVarTo);
		runRExp(rc, rowNames);
	}

	public static void average(RConnection rc, List<String> columnNames, String normData, String columnName) throws REngineException,
			REXPMismatchException {
		String rowMeansFunction = "rowMeans(%s[ , c(\"%s\")])->%s";
		rowMeansFunction = String.format(rowMeansFunction, normData, StringUtils.join(columnNames, "\",\""), columnName);
		runRExp(rc, rowMeansFunction);

		frameFunction(rc, columnName.toString(), columnName.toString());
		assignRowNames(rc,  normData, columnName.toString());
	}

	public static String boxplot(String tableVar, String ylabel, String xlabels) {
//		String vX = "";
//		if(verticalX)
//			vX = " las=2, cex.axis=0.8, ";
//		return String.format("boxplot(%s, ylab=\"%s\", names=%s,%sborder=%s)", tableVar, ylabel, xlabels,vX, RUtils.combine(Arrays.asList(colors)));
		if(xlabels == ""){
			xlabels="\"\"";
			return String.format("boxplot(%s, ylab=\"%s\", xaxt=\"n\", xlab=%s, border=%s)", tableVar, ylabel, xlabels,  RUtils.combine(Arrays.asList(colors)));
		}
		return String.format("boxplot(%s, ylab=\"%s\", names=%s, border=%s)", tableVar, ylabel, xlabels,  RUtils.combine(Arrays.asList(colors)));
	}

	public static void cbind(RConnection rc, List<String> tables, String combined) throws REngineException, REXPMismatchException {
		String cBind = String.format("cbind(%s)->%s", StringUtils.join(tables, ","), combined);
		runRExp(rc, cBind);
	}

	public static void colNames(RConnection rc, String tableVarFrom, String tableVarTo) throws REngineException, REXPMismatchException {
		String colNames = String.format("colnames(%s)<-colnames(%s);", tableVarTo, tableVarFrom);
		runRExp(rc, colNames);
	}

	public static String combine(List<?> strings) {
		return "c(\"" + StringUtils.join(strings, "\", \"") + "\")";
	}

	// call after plotting
	public static void devOff(RConnection rc) throws REngineException, REXPMismatchException {
		runRExp(rc, "dev.off()");
	}

	public static String filterTable(String table, String rows, String columns) {
		return String.format("%s[%s,%s]", table, rows, columns);
	}

	public static void frameFunction(RConnection rc, String columName, String outVar) throws REngineException, REXPMismatchException {
		String frameFunction = String.format("as.data.frame(%s)->%s", columName, outVar);
		runRExp(rc, frameFunction);
	}

	// normData2<-2^normData2
	public static void linearizeLog2(RConnection rc, String dataVarIn, String dataVarOut) throws REngineException, REXPMismatchException {
		String linearizelog2 = String.format("%s<-2^%s", dataVarOut, dataVarIn);
		runRExp(rc, linearizelog2);
	}

	public static void loadLibrary(RConnection rc, String library) throws REngineException, REXPMismatchException {
		runRExp(rc, String.format("library(%s)", library));
	}

	public static void loadWorkSpace(RConnection rc, String workspaceLocation) throws REngineException, REXPMismatchException {
		String loadWorkspaceCommand = String.format("load(\"%s\")", workspaceLocation);
		runRExp(rc, loadWorkspaceCommand);
	}

	public static String log2(String varIn) {
		return String.format("log(%s,2)", varIn);
	}

	public static void mergeByRow(RConnection rc, String table1, String table2, String combined) throws REngineException, REXPMismatchException {
		String cBind = String.format("merge(%s,%s, by = \"row.names\", all = TRUE)->%s", table1, table2, combined);
		runRExp(rc, cBind);
	}

	public static String mget(String tableVarName, String get) {
		return String.format("mget(rownames(%s),%s,ifnotfound=NA);", tableVarName, get);
	}

	public static String plot(String varToPlot, String ylab, String xlab) {
		return String.format("plot(%s, ylab=\"%s\", xlab=\"%s\");", varToPlot, ylab, xlab);
	}

	public static String png(String fileName) {
		return String.format("png(\"%s\")", fileName);
	}

	public static void pracmaLibrary(RConnection rc) throws REngineException, REXPMismatchException {
		loadLibrary(rc, "pracma");
	}

	public static String round(String table, Integer digit) {
		return String.format("round(%s, %s)", table, digit);
	}

	public static void rowNames(RConnection rc, String tableVarFrom, String varOut) throws REngineException, REXPMismatchException {
		String rowNames = String.format("rownames(%s)->%s;",  tableVarFrom, varOut);
		runRExp(rc, rowNames);
	}
	
	public static void rowSums(RConnection rc, String matrixVar, String outVar) throws REngineException, REXPMismatchException {
		String rowSums = String.format("rowSums(%s)->%s", matrixVar, outVar);
		runRExp(rc, rowSums);
	}
	
	public static void asMatrix(RConnection rc, String var, String outVar) throws REngineException, REXPMismatchException{
		String asMatrix = String.format("as.matrix(%s)->%s", var, outVar);
		runRExp(rc, asMatrix);
	}

	public static REXP runRExp(RConnection rc, String rexp) throws REngineException, REXPMismatchException {
		System.out.println(rexp);
		
		return rc.parseAndEval(rexp);
	}

	public static File saveWorkspace(RConnection rc) throws REngineException, REXPMismatchException, IOException {
		File workspaceFile = File.createTempFile("workspace_", ".RData");
		workspaceFile.deleteOnExit();
		String workspaceFileOut = workspaceFile.getAbsolutePath().replace("\\", "/");
		runRExp(rc, String.format("save.image(\"%s\")", workspaceFileOut));
		return workspaceFile;
	}

	public static void unlistCharacter(RConnection rc, String listVar, String unlistChararcterVar) throws REngineException, REXPMismatchException {
		String unlistCharacter = String.format("as.character(unlist(%s))->>%s", listVar, unlistChararcterVar);
		runRExp(rc, unlistCharacter);
	}

	public static void writeTable(RConnection rc, String variable, String file, String colNames, String rowNames) throws REngineException,
			REXPMismatchException {
		String writeExp = String.format("write.table(%s, file=\"%s\", col.names=%s, row.names=%s, sep=\"\\t\")", variable, file, colNames, rowNames);
		runRExp(rc, writeExp);
	}
	
	public static String tableRowsColsSelection(String table, String rows, String cols){
		return String.format("%s[%s,%s]", table, rows, cols);
	}

	public static String dist(String table){
		return String.format("dist(t(%s),method='euclidean')", table);
	}

}
